PrepareLevel3:
	;; split prepare common into two parts
	;; since want score above road for twoplayer
	bsr	PrepareLevelCommonPart1

	;; copy ground tiles over VRAM 2000
        move.l   #$60000000,(a4)
        lea      StartROAD6Tiles(pc),a5
        move.w   #((EndROAD6Tiles-StartROAD6Tiles)/2-1),d5
Road6TileCopy:
        move.w   (a5)+,(a3)
        dbf      d5,Road6TileCopy

	;; copy road6 tiles
	move.w	#31,d0
	;; VRAM C780
	move.l	#$47800003,d1
Level3Road6MapLoop:	
	lea     StartROAD6Map(pc),a5
	move.w  #$0100,d4
        moveq   #(ROAD6TileWidth-1),d5
        moveq   #(ROAD6TileHeight-1),d6
	move.l	d1,d7
	addi.l	#$00040000,d1
	bsr	CopyMap
	dbf     d0,Level3Road6MapLoop

	move.w	#$0000,Level3TruckPositionX
	move.w	#$0000,Level3TruckSpeed
	move.l	#$0001B800,Level3LetterPositionX

	btst	#TwoPlayerFlag,Flags
	bne.s	PrepareLevel3TwoPlayer

PrepareLevel3OnePlayer:	
	move.l	#$00013400,Level3TruckPositionY
	move.w	#$0134,Level3TruckDesiredY

	lea	StartSpriteLevel3Initial(pc),a5
	;; sprite load follows branch
	bra.s	PrepareLevel3Final
	
PrepareLevel3TwoPlayer:
	;; copy road6 tiles
	move.w	#31,d0
	;; VRAM C480
	move.l	#$40800003,d1
Level3TwoPlayerRoad6MapLoop:	
	lea     StartROAD6Map(pc),a5
	move.w  #$0100,d4
        moveq   #(ROAD6TileWidth-1),d5
        moveq   #(ROAD6TileHeight-1),d6
	move.l	d1,d7
	addi.l	#$00040000,d1
	bsr	CopyMap
	dbf     d0,Level3TwoPlayerRoad6MapLoop

	move.l	#$0000C400,Level3TruckPositionY
	move.w	#$00C4,Level3TruckDesiredY

	move.w	#$0000,Level3Truck2PositionX
	move.l	#$00013400,Level3Truck2PositionY
	move.w	#$0134,Level3Truck2DesiredY
	move.w	#$0000,Level3Truck2Speed
	move.l	#$0001B800,Level3Letter2PositionX

	lea	StartSpriteLevel3TwoPlayerInitial(pc),a5

PrepareLevel3Final:	
	bsr	SpriteLoad

	;; VRAM C784
	move.l	#$47840003,d7
	bsr	PrepareLevelCommonPart2

	lea	Level3Animate(pc),a5
	move.l	a5,VintAnimate

	bsr	Level3RefreshLetters
	bsr	FadeIn

Level3Loop:
	bsr	WaitForVint

	;; demo mode check
	btst	#DemoFlag,Flags
	beq.s	Level3SkipDemoMode
	;; in demo mode, exit on button press
	btst	#StartButtonFlag,Flags
	bne	PrepareTitleFadeOut
	;; demo only shows for a certain amount of frames
	cmpi.w	#VintWaitDemo,VintWait
	bge	PrepareTitleFadeOut
	;; do not set up or down buttons
	;; just override the desired y location of the truck directly
	;; based on the letter position
	move.w	LetterSprite,d0
	subi.w	#24,d0
	move.w	d0,Level3TruckDesiredY
	move.w	Letter2Sprite,d0
	subi.w	#24,d0
	move.w	d0,Level3Truck2DesiredY
	;; demo always has the pedal to the medal
	move.b	#btnC,Port1Hold
	move.b	#btnC,Port2Hold
Level3SkipDemoMode:	

	;; check for sprite collision
	move.w   (a4),d0
	andi.b   #$0020,d0
	beq      Level3DetermineTruckSpeed1

	;; there is a sprite collision
	;; see if letter already $00 (end of word)
	tst.b    LetterSprite+5
	beq.s    Level3Player2Collision
	;; collision check
	lea	TruckLeftSprite,a5
	lea	LetterSprite,a6
	bsr	CheckSpriteInsideAnotherSprite
	bne.s	Level3Player2Collision

	;; now update the score
	lea     EndScoreAscii,a5
        move.l  #$40900003,d0
	move.w  #(EndScoreAscii-StartScoreAscii-1),d1
	clr.w	d2
	move.b  WordIndex,d2
	;; make high priority (so score will go above other things)
	move.w  #$8000,d4
	bsr	UpdateAndDisplayScoreAndWord

	;; get next character
	clr.w	d0
	move.b  WordIndex,d0
	clr.w	d1
	move.b  WordIndex2,d1
	bsr	GetNextLetter
	move.b	d0,WordIndex

	clr.b	LetterSprite+5
	move.l	#$0001B800,Level3LetterPositionX
	
Level3Player2Collision:	
	btst	#TwoPlayerFlag,Flags
	beq.s	Level3CheckRefreshLetters
	;; see if letter already $00 (end of word)
	tst.b   Letter2Sprite+5
	beq.s   Level3CheckRefreshLetters
	;; collision check
	lea	Truck2LeftSprite,a5
	lea	Letter2Sprite,a6
	bsr	CheckSpriteInsideAnotherSprite
	bne.s	Level3CheckRefreshLetters

	;; now update the score ($30-$39 are valid ASCII numbers)
	lea     EndScoreAscii2,a5
        move.l  #$47900003,d0
	move.w  #(EndScoreAscii2-StartScoreAscii2-1),d1
	clr.w	d2
	move.b  WordIndex2,d2
	;; make high priority (so score will go above other things)
	move.w  #$A000,d4
	bsr	UpdateAndDisplayScoreAndWord

	;; get next character
	clr.w	d0
	move.b  WordIndex2,d0
	clr.w	d1
	move.b  WordIndex,d1
	bsr	GetNextLetter
	move.b	d0,WordIndex2

	clr.b	Letter2Sprite+5
	move.l	#$0001B800,Level3Letter2PositionX
	
Level3CheckRefreshLetters:	
	bclr	#RefreshLettersWordFlag,WordFlags
	beq.s	Level3CheckNewWord
	bsr.s	Level3RefreshLetters
	
Level3CheckNewWord:	
	bclr	#NewWordFlag,WordFlags
	beq.s	Level3CheckNewLevel
	;; set x positions of letters to same starting point
	move.l	#$0001B800,Level3LetterPositionX
	move.l	#$0001B800,Level3Letter2PositionX

Level3CheckNewLevel:	
	;; check if need to go to next level
	;; demo cannot go to another level
	bclr	#NewLevelFlag,WordFlags
	beq.s	Level3DetermineTruckSpeed1
	btst	#DemoFlag,Flags
	bne.s	Level3DetermineTruckSpeed1
	bsr	LevelTransition
	bra	PrepareLevel4
	
Level3DetermineTruckSpeed1:	
	lea     Level3TruckPositionX,a5
	lea	TruckLeftSprite,a6
	move.b	Port1Hold,d0
	bsr	Level3DetermineTruckSpeed
Level3DetermineTruckSpeed2:	
	lea     Level3Truck2PositionX,a5
	lea	Truck2LeftSprite,a6
	move.b	Port2Hold,d0
	bsr	Level3DetermineTruckSpeed

EndLevel3Loop:	
	bra	Level3Loop


	;; updates letters, and for level 1 the letter x and y positions
	;; no inputs
	;; destroys a5
Level3RefreshLetters:	
	bsr	RefreshLetters

	movem.w d0-d3,-(a7)

	;; update letter y location
	lea	StartWordY,a5

	clr.l	d1
	clr.l	d3
	move.b	WordIndex,d0
	move.b	WordIndex2,d2
	move.b	(a5,d0.w),d1
	move.b	(a5,d2.w),d3
	;; 256/6 = 42.67, round up to 43
	;; that way we don't need to shift the remainder and can use the
	;; quotient instead
	divu.w	#43,d1
	divu.w	#43,d3
	andi.b  #$07,d1
	andi.b  #$07,d3
	;; multiply the height of a lane
	mulu.w	#15,d1
	mulu.w	#15,d3
	;; different letter positions for player 1 depending on 1/2 player
	btst	#TwoPlayerFlag,Flags
        bne.s	Level3RefreshLettersTwoPlayer
	addi.w  #($80+15*8+9),d1
	bra.s   Level3RefreshLettersDone
Level3RefreshLettersTwoPlayer:	
	addi.w  #($80+8+9),d1
Level3RefreshLettersDone:	
	addi.w  #($80+15*8+9),d3

	move.w  d1,LetterSprite+0
	move.w  d3,Letter2Sprite+0

	movem.w (a7)+,d0-d3
	rts


Level3Animate:
	movem.l	d0-d2/a5,-(a7)

	;; get speed
	clr.l	d1
	move.w	Level3TruckSpeed,d1
	move.l	d1,d2

	move.w	TruckLeftSprite,d0
	cmp.w	Level3TruckDesiredY,d0
	beq.s	Level3AnimateSkipMoveTruck

	;; refine speed x (d1) y (d2) for changing lanes
	;; calculate (speed*(sin(30 degrees)*256))/256
	mulu.w	#128,d2
	lsr.l	#8,d2
	;; calculate (speed*(cos(30 degrees)*256))/256
	mulu.w	#222,d1
	lsr.l	#8,d1
	
	cmp.w	Level3TruckDesiredY,d0
	blt.s	Level3AnimateMoveTruckDown
Level3AnimateMoveTruckUp:	
	move.l	Level3TruckPositionY,d0
	sub.l	d2,d0

	;; make sure we don't go beyond desired
	clr.l	d2
	move.w	Level3TruckDesiredY,d2
	lsl.l	#8,d2
	cmp.l	d2,d0
	blt.s	Level3AnimateMoveTruckToDesiredY
	bra.s	Level3AnimateMoveTruckUpAndDownCommon

Level3AnimateMoveTruckDown:
	move.l	Level3TruckPositionY,d0
	add.l	d2,d0

	;; make sure we don't go beyond desired
	clr.l	d2
	move.w	Level3TruckDesiredY,d2
	lsl.l	#8,d2
	cmp.l	d2,d0
	blt.s	Level3AnimateMoveTruckUpAndDownCommon

Level3AnimateMoveTruckToDesiredY:	
	move.l	d2,d0

Level3AnimateMoveTruckUpAndDownCommon:
	move.l	d0,Level3TruckPositionY
	lsr.l	#8,d0
	move.w	d0,TruckLeftSprite
	move.w	d0,TruckRightSprite

Level3AnimateSkipMoveTruck:	

	;; move letter to the left
	move.l	Level3LetterPositionX,d0
	sub.l	d1,d0
	cmpi.l	#$00007000,d0
	bgt.s	Level3SkipResetLetterX
	;; wrap around the letter to the right side of the screen
	move.l	#$0001B800,d0
Level3SkipResetLetterX:	
	move.l	d0,Level3LetterPositionX
	lsr.l	#8,d0
	move.w	d0,LetterSprite+6

	;; determine road position
	move.w	Level3TruckPositionX,d0
	sub.w	d1,d0
	move.w	Level3TruckPositionX,d1
	eor.w	d0,d1
	move.w	d0,Level3TruckPositionX
	
	;; animate tires of truck
	andi.w  #$1000,d1
        beq.s	Level3AnimateSkipTruck1TireSpinAnimate
	lea	TruckLeftSprite,a5
	bsr 	TruckTireSpinAnimate
Level3AnimateSkipTruck1TireSpinAnimate:	

	clr.w	d0
	move.b	Level3TruckPositionX,d0

	btst	#TwoPlayerFlag,Flags
        beq	Level3AnimateOnePlayer
	
	;; VRAM DC00+0140
	move.l	#$5D400003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5D200003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5CE00003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5CA00003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5C600003,(a4)
	move.w	d0,(a3)

	;; get speed x (d1) y (d2)
	clr.l	d1
	move.w	Level3Truck2Speed,d1
	move.l	d1,d2

	move.w	Truck2LeftSprite,d0
	cmp.w	Level3Truck2DesiredY,d0
	beq.s	Level3AnimateSkipMoveTruck2

	;; refine speed x (d1) y (d2) for changing lanes
	;; calculate (speed*(sin(30 degrees)*256))/256
	mulu.w	#128,d2
	lsr.l	#8,d2
	;; calculate (speed*(cos(30 degrees)*256))/256
	mulu.w	#222,d1
	lsr.l	#8,d1
	
	cmp.w	Level3Truck2DesiredY,d0
	blt.s	Level3AnimateMoveTruck2Down
Level3AnimateMoveTruck2Up:	
	move.l	Level3Truck2PositionY,d0
	sub.l	d2,d0

	;; make sure we don't go beyond desired
	clr.l	d2
	move.w	Level3Truck2DesiredY,d2
	lsl.l	#8,d2
	cmp.l	d2,d0
	blt.s	Level3AnimateMoveTruck2ToDesiredY

	bra.s	Level3AnimateMoveTruck2UpAndDownCommon

Level3AnimateMoveTruck2Down:
	move.l	Level3Truck2PositionY,d0
	add.l	d2,d0

	;; make sure we don't go beyond desired
	clr.l	d2
	move.w	Level3Truck2DesiredY,d2
	lsl.l	#8,d2
	cmp.l	d2,d0
	blt.s	Level3AnimateMoveTruck2UpAndDownCommon

Level3AnimateMoveTruck2ToDesiredY:	
	move.l	d2,d0

Level3AnimateMoveTruck2UpAndDownCommon:
	move.l	d0,Level3Truck2PositionY
	lsr.l	#8,d0
	move.w	d0,Truck2LeftSprite
	move.w	d0,Truck2RightSprite

Level3AnimateSkipMoveTruck2:	

	;; move letter 2 to the left
	move.l	Level3Letter2PositionX,d0
	sub.l	d1,d0
	cmpi.l	#$00007000,d0
	bgt.s	Level3SkipResetLetter2X
	;; wrap around the letter to the right side of the screen
	move.l	#$0001B800,d0
Level3SkipResetLetter2X:	
	move.l	d0,Level3Letter2PositionX
	lsr.l	#8,d0
	move.w	d0,Letter2Sprite+6

	move.w	Level3Truck2PositionX,d0
	sub.w	d1,d0
	move.w	Level3Truck2PositionX,d1
	eor.w	d0,d1
	move.w	d0,Level3Truck2PositionX
	
	;; animate tires of truck
        andi.w  #$1000,d1
        beq.s	Level3AnimateSkipTruck2TireSpinAnimate
	lea	Truck2LeftSprite,a5
	bsr 	TruckTireSpinAnimate
Level3AnimateSkipTruck2TireSpinAnimate:	

	clr.w	d0
	move.b	Level3Truck2PositionX,d0

Level3AnimateOnePlayer:	

	;; VRAM DC00+0300
	move.l	#$5F000003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5EE00003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5EA00003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5E600003,(a4)
	move.w	d0,(a3)
	;; VRAM DC00+
	move.l	#$5E200003,(a4)
	move.w	d0,(a3)

	movem.l	(a7)+,d0-d2/a5
	rts



	;; (a5).w has truck speed
	;; a6 has TruckLeftSprite/Truck2LeftSprite
	;; d0.b	has port 1/2 hold
	;; destroys d1.l
Level3DetermineTruckSpeed:
	;; get Level3TruckSpeed/Level3Truck2Speed
	move.w	8(a5),d1

	;; check if braking (B) held
	btst	#bitB,d0
	bne.s	Level3DetermineTruckSpeedBraking

	;; check if gas (A) or (C) held
	btst	#bitA,d0
	bne.s	Level3DetermineTruckSpeedGas
	btst	#bitC,d0
	bne.s	Level3DetermineTruckSpeedGas

	;; coasting
	subq.w	#Level3DeaccelerationCoast,d1
	bra.s	Level3DetermineTruckSpeedAvoidReverse

Level3DetermineTruckSpeedGas:
	;; applying gas
	addi.w	#Level3AccelerationGas,d1
	;; check against max speed
	cmpi.w	#Level3MaxSpeed,d1
	ble.s	Level3DetermineTruckSpeedDone
	;; cap speed to the max speed
	move.w	#Level3MaxSpeed,d1
	bra.s	Level3DetermineTruckSpeedDone

Level3DetermineTruckSpeedBraking:
	;; braking, faster stop than coasting
	subi.w	#Level3DeaccelerationBrake,d1
	
Level3DetermineTruckSpeedAvoidReverse:
	;; make sure speed is not negative (use branch plus)
	tst.w	d1
	bpl.s	Level3DetermineTruckSpeedDone
	;; cap speed to zero to avoid reverse
	clr.w	d1

Level3DetermineTruckSpeedDone:
	;; save Level3TruckSpeed/Level3Truck2Speed
	move.w	d1,8(a5)

	;; if not moving, cannot change lanes
	tst.w	d1
	beq.s	Level3MoveTruckDone
	
	;; get Level3TruckDesiredY/Level3Truck2DesiredY
	move.w	6(a5),d1

	;; allow changing direction even if already in a lane change manuever
	cmp.w	(a6),d1
	blt.s	Level3MoveTruckCheckMoveDown

	bne.s	Level3MoveTruckDone

	btst	#bitUp,d0
	bne.s	Level3MoveTruckUp
Level3MoveTruckCheckMoveDown:	

	cmp.w	(a6),d1
	bgt.s	Level3MoveTruckDone

	btst	#bitDown,d0
	beq.s	Level3MoveTruckDone

Level3MoveTruckDown:	
	;; check if bottom lane
	cmpi.w	#$00C4,d1
	beq.s	Level3MoveTruckDone
	cmpi.w	#$0134,d1
	bge.s	Level3MoveTruckDone
	addi.w	#15,d1
	bra.s	Level3MoveTruckSave
	
Level3MoveTruckUp:
	;; check if top lane
	cmpi.w	#$0079,d1
	ble.s	Level3MoveTruckDone
	cmpi.w	#$00E9,d1
	beq.s	Level3MoveTruckDone
	subi.w	#15,d1
	
Level3MoveTruckSave:
	;; save Level3TruckDesiredY/Level3Truck2DesiredY
	move.w	d1,6(a5)

Level3MoveTruckDone:
	
	rts

	
;;; data used for level 2


StartSpriteLevel3Initial:
	dc.b $01,$2C,$06,$01,$48,$80,$01,$E0
TruckLeftSpriteLevel3Initial:
	dc.b $01,$34,$0F,$02,$00,$AD,$00,$D7
TruckRightSpriteLevel3Initial:
	dc.b $01,$34,$0B,$04,$00,$BD,$00,$F7
	dc.b $00,$00,$00,$00,$00,$00,$00,$00
LetterSpriteLevel3Initial:
	dc.b $01,$04,$00,$00,$00,$41,$01,$B8
EndSpriteLevel3Initial:	

StartSpriteLevel3TwoPlayerInitial:
	dc.b $01,$2C,$06,$01,$48,$80,$01,$E0
TruckLeftSpriteLevel3TwoPlayerInitial:
	dc.b $00,$C4,$0F,$02,$00,$AD,$00,$D7
TruckRightSpriteLevel3TwoPlayerInitial:
	dc.b $00,$C4,$0B,$04,$00,$BD,$00,$F7
	dc.b $00,$00,$00,$00,$00,$00,$00,$00
LetterSpriteLevel3TwoPlayerInitial:
	dc.b $00,$94,$00,$06,$00,$41,$01,$B8
	dc.b $00,$00,$00,$00,$00,$00,$00,$00
Truck2LeftSpriteLevel3TwoPlayerInitial:
	dc.b $01,$34,$0F,$07,$20,$AD,$00,$D7
Truck2RightSpriteLevel3TwoPlayerInitial:
	dc.b $01,$34,$0B,$09,$20,$BD,$00,$F7
	dc.b $00,$00,$00,$00,$00,$00,$00,$00
Letter2SpriteLevel3TwoPlayerInitial:
	dc.b $01,$04,$00,$00,$20,$41,$01,$B8
EndSpriteLevel3TwoPlayerInitial:	
	